package dosgi.distribution.remote.impl;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.util.Map;
import java.util.UUID;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;

import dosgi.distribution.Activator;
import dosgi.distribution.RemoteInvocationArguments;
import dosgi.distribution.remote.RemoteInvocationClient;

public class RemoteInvocationClientImpl implements RemoteInvocationClient {
	
	private ConnectionFactory factory;
	private Connection connection;
	private Channel channel;
	private String replyQueueName;
	private QueueingConsumer consumer;
	
	public RemoteInvocationClientImpl() throws Exception {
		factory = new ConnectionFactory();

		// TODO pobieranie konfiguracji z pliku!
		factory.setHost("nn.evizone.icsadl.agh.edu.pl");

		connection = factory.newConnection();
		channel = connection.createChannel();

		// kolejka bedzie miala nazwe autowygenerowana
		replyQueueName = channel.queueDeclare().getQueue();

		int prefetchCount = 1;
		channel.basicQos(prefetchCount);

		consumer = new QueueingConsumer(channel);
		channel.basicConsume(replyQueueName, true, consumer);
	}

	@Override
	public Object invoke(String className, String methodName, Map<Class<?>, Object> args, Map<String, String> properties, String queueName) throws Exception {
		Object response = null;
		String corrId = UUID.randomUUID().toString();
		
		BasicProperties props = new BasicProperties.Builder().correlationId(corrId).replyTo(replyQueueName).build();
		RemoteInvocationArguments arguments = new RemoteInvocationArguments.Builder().className(className).methodName(methodName).arguments(args).properties(properties).build();
		channel.basicPublish("", queueName, props, arguments.toByteArray());
		
		while (true) {
			QueueingConsumer.Delivery delivery = consumer.nextDelivery();
			if (delivery.getProperties().getCorrelationId().equals(corrId)) {
				response = getFromByteArray(delivery.getBody());
				break;
			}
		}
		return response;
	}

	@Override
	public String getQueueName() {
		return Activator.QUEUE_NAME;
	}
	
	@Override
	public void close() throws Exception {
		channel.close();
		connection.close();
	}
	
	private Object getFromByteArray(byte[] body) throws IOException, ClassNotFoundException {
		ObjectInput in;
		ByteArrayInputStream bais = new ByteArrayInputStream(body);
		in = new ObjectInputStream(bais);
		Object res = in.readObject();
		return res;
	}

}
